<!--
 * @Author       : Hejh(3010733382@qq.com)
 * @Version      : V1.0
 * @Date         : 2024-02-07 11:37:50
 * @Description  : 封装的数据表格展示组件，合并了分页组件
-->
<template>
  <n-data-table
    :remote="true"
    class="con"
    :striped="true"
    :bordered="false"
    :checked-row-keys="checkedRowKeys.map((item) => item.id || item)"
    :columns="columns"
    :data="data"
    ref="tableRef"
    :pagination="pagination"
    :max-height="maxHeight"
    :scroll-x="scrollX"
    :row-props="rowProps"
    :row-key="(rowData: IndexObj) => rowData.id"
    size="small"
    :cascade="false"
    @update:checked-row-keys="handleCheck"
    @update-sorter="handleUpdateSorter"
    @load="handleLoad"
    :allow-checking-not-loaded="true"
  />
</template>

<script lang="ts" setup>
import type { IndexObj } from '@/types/commom'
import { NButton } from 'naive-ui'
import type { PaginationProps } from 'naive-ui'
import Sortable from 'sortablejs'

const props = withDefaults(
  defineProps<{
    draggable?: boolean
    data: IndexObj[] // 传入的data数据
    columns: IndexObj[] // 传入的data模型
    checkedRowKeys: any[] // 选中的行
    pages: number
    total: number
    pageSize?: number
    handleLoad?: any
    isSort?: boolean // 是否需要拖拽排序功能
    onContextmenu?: any
    maxHeight?: any
    onlyCheckAll?: boolean // 只允许全选
  }>(),
  {
    draggable: false,
    handleLoad: undefined,
    load: true,
    isSort: true,
    maxHeight: 400,
    onlyCheckAll: false,
    onContextmenu: (row: IndexObj) => {
      return () => {}
    }
  }
)

const emits = defineEmits<{
  (e: 'pageChange', page?: number, pageSize?: number): void
  (e: 'selectChange', selectKeys: any[], selectRows: any[]): void
  (e: 'itemClick', clickRow: any): void
  (e: 'itemDbClick', clickRow: any): void
  (e: 'sortChange', sorter: IndexObj): void // 表格按某个字段进行排序
  (e: 'orderChange', newIndex: number, oldIndex: number): void // 拖拽排序
  (e: 'mouseover', row: any, event: MouseEvent): void
  (e: 'mousedown', row: any, event: MouseEvent): void
  (e: 'mouseleave', row: any, event: MouseEvent): void
  (e: 'drop', row: any, event: DragEvent): void
  (e: 'dragover', row: any, event: DragEvent): void
}>()

const computedCheckRows = computed(() => {
  return props.checkedRowKeys.map((item) => item.id || item)
})

// 表格项被单击
const rowProps = (row: IndexObj) => {
  return {
    draggable: props.draggable,
    class: computedCheckRows.value.includes(row.id)
      ? 'n-data-table-tr selected'
      : 'n-data-table-tr',
    onClick: (e: MouseEvent) => {
      e.stopPropagation()
      if (e.shiftKey) {
        let firstIndex = 0
        if (props.checkedRowKeys.length > 0) {
          const index = props.data.findIndex(
            (item) => item.id === props.checkedRowKeys[0].id
          )
          firstIndex = index === -1 ? 0 : index
        }
        const lastIndex = props.data.findIndex((item) => item.id === row.id)
        const minIndex = Math.min(firstIndex, lastIndex)
        const maxIndex = Math.max(firstIndex, lastIndex)

        console.log(minIndex, maxIndex)

        const selectRows = props.data.slice(minIndex, maxIndex + 1)
        emits(
          'selectChange',
          selectRows.map((item) => item.id),
          selectRows
        )
        // 清除选择的文字区域
        // window.getSelection().removeAllRanges()
        return
      } else if (e.ctrlKey) {
        console.log('ctrl key')
        emits('itemClick', row)
        return
      }
      // console.log(lastIndex.value, index)
      // lastIndex.value = index
      // console.dir(e.target as any)

      if ((e.target as any).className.includes('n-checkbox-box__border')) {
        emits('itemClick', row)
      } else {
        emits('selectChange', [row.id], [row])
      }
      // emits('itemClick', row)
    },
    ondblclick: (e: MouseEvent) => {
      e.stopPropagation()
      emits('itemDbClick', row)
    },
    onContextmenu: props.onContextmenu(row),
    onmouseover: (e: MouseEvent) => {
      // console.log('enter')
      emits('mouseover', row, e)
    },
    onmouseleave: (e: MouseEvent) => {
      // console.log('leave')
      emits('mouseleave', row, e)
    },
    onmousedown: (e: MouseEvent) => {
      emits('mousedown', row, e)
    },
    ondragover: (e: DragEvent) => {
      // if(row.isDir&&)
      // e.preventDefault()
      emits('dragover', row, e)
    },
    onDrop: (e: DragEvent) => {
      // e.preventDefault()
      // e.stopPropagation()
      emits('drop', row, e)
    }
  }
}

const cnt = ref(0)
// 表格多选
const handleCheck = (keys: any[], rows: IndexObj[], meta: any) => {
  // console.log(meta)

  if (props.onlyCheckAll) {
    if (!['checkAll', 'uncheckAll'].includes(meta.action)) {
      return
    }

    cnt.value++
    if (cnt.value % 2 === 0) {
      meta.action = 'uncheckAll'
    } else {
      meta.action = 'checkAll'
    }

    if (meta.action === 'uncheckAll') {
      emits('selectChange', [], [])
      return
    }
  }
  // console.log(keys)

  // 统一一点，将row.id还是整个row
  emits('selectChange', keys, rows)
}

// 分页查询后同步到分页器
watch(
  props,
  (newValue) => {
    pagination.pageCount = newValue.pages
    pagination.itemCount = newValue.total
  },
  {
    deep: true
  }
)

// 根据columns设置的min-width计算出横向滚动阈值
const scrollX = computed(() => {
  return props.columns.reduce((pre, next) => {
    pre = pre + next.minWidth
    return pre
  }, 0)
})

// 表格对于的分页配置
const pagination = reactive<PaginationProps>({
  page: 1,
  pageSize: props.pageSize || 50,
  size: 'small',
  pageCount: props.pages,
  itemCount: props.total,
  pageSlot: 7,
  showSizePicker: true,
  label: (info) => {
    return h(
      NButton,
      {
        type: info.active ? 'primary' : 'tertiary',
        secondary: !info.active,
        style: {
          width: '100%',
          height: '100%'
        }
      },
      { default: () => info.node }
    )
  },
  suffix({ itemCount }) {
    return `${itemCount}条记录`
  },
  pageSizes: [
    {
      label: '10条/每页',
      value: 10
    },
    {
      label: '50条/每页',
      value: 50
    },
    {
      label: '100条/每页',
      value: 100
    },
    {
      label: '200条/每页',
      value: 200
    },
    {
      label: '500条/每页',
      value: 500
    },
    {
      label: '1000条/每页',
      value: 1000
    },
    {
      label: '2000条/每页',
      value: 2000
    }
  ],
  onChange: (page: number) => {
    pagination.page = page
    emits('pageChange', page, undefined)
  },
  onUpdatePageSize: (pageSize: number) => {
    pagination.pageSize = pageSize
    pagination.page = 1
    emits('pageChange', 1, pageSize)
  }
})

const tableRef = ref()
const sortable = ref()

defineExpose({
  tableRef
})

const timer = ref()
// 排序功能添加
function setSort() {
  timer.value = setInterval(() => {
    const el = tableRef.value.$el.querySelector(
      '.n-data-table-wrapper .n-data-table-base-table .n-data-table-base-table-body tbody.n-data-table-tbody'
    )
    if (!el) {
      return
    }

    sortable.value = Sortable.create(el, {
      ghostClass: 'sortable-ghost',
      handle: '.my-handle',
      setData: function (dataTransfer: any) {
        dataTransfer.setData('Text', '')
      },
      onStart: function (/**Event*/ evt) {
        evt.oldIndex // element index within parent
      },
      onEnd: (e) => {
        // e.originalEvent.dataTransfer.dropEffect = 'move'
        //这里拖拽结束可以进行项目中的业务逻辑代码,e值可在文档配置中找到需要的配置值
        if (e.newIndex !== undefined && e.oldIndex !== undefined) {
          if (e.newIndex !== e.oldIndex) {
            emits('orderChange', e.newIndex, e.oldIndex)
          }
        }
      }
    })
    clearInterval(timer.value)
  }, 1000)
}

// 字段筛选被点击
const handleUpdateSorter = (sorter: IndexObj) => {
  emits('sortChange', sorter)
}

// data挂载完成，进行sort的挂载
onMounted(() => {
  // data加载完成后，进行sortable的挂载
  if (props.isSort) {
    setSort()
  }
})

onBeforeUnmount(() => {
  if (props.isSort) {
    clearInterval(timer.value)
  }
})
</script>

<style scoped lang="scss">
.con {
  font-size: 13px;

  :deep(.n-pagination .n-pagination-item) {
    padding: 0 !important;
    border: 0;
    width: 25px !important;
    height: 25px !important;
    min-width: 25px;

    & .n-button {
      height: 100%;
      width: 100%;
      min-width: 25px;
      min-height: 25px;
      padding: 0;
      margin: 0;
    }
  }

  :deep(label) {
    margin-bottom: 0;
  }

  :deep(.sortable-ghost td) {
    opacity: 0.2;
    color: #fff !important;
    background: $primaryColor-2 !important;
  }

  :deep(
      .n-data-table-th .n-data-table-th__title-wrapper .n-data-table-th__title
    ) {
    font-weight: 800;
    color: #888;
  }
}
</style>
